/*
*Function:linux-0.11下信号量解决消费者生产者问题，使用文件作为共享缓冲区
*Author:
*/

#define __LIBRARY__            /*切记：这个一定要加，否则unistd.h中的宏无法使用，切记！*/
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>

#define N 4
#define BUFFER_SIZE 10

sem_t* sem_open(const char *name,int ignore1,int ignore2,unsigned int value)
{
	long _res;
	__asm__ volatile ("int $0x80"
	                  : "=a" (_res)
	                  : "0" (__NR_sem_open),"b" ((long)(name)),"c" ((long)(value)));
	
	   return (sem_t *)_res;
}
_syscall1(int,sem_unlink,const char *,name)
_syscall1(int,sem_wait,sem_t *,sema)
_syscall1(int,sem_post,sem_t *,sema)
_syscall2(int,sem_getvalue,sem_t *,sema,int *,valsem)

int main()
{
	int i,j,k,in=0;
	int fd;
	sem_t *mutex,*full,*empty,*out;

	if((fd = open("/var/buffer.txt",O_CREAT|O_RDWR,0666)) < 0)   /*创建文件作为共享缓冲区*/
	{
		printf("Error: Fail to creat buffer!\n");
		exit(1);
	}
    mutex = sem_open("mutex",O_CREAT,0644,1);    
	full = sem_open("full",O_CREAT,0644,0);    /*数字资源信号量*/
	empty = sem_open("empty",O_CREAT,0644,BUFFER_SIZE);  /*空格信号量*/
	out = sem_open("out",O_CREAT,0644,0);   /*表征当前读的位置*/
	
	lseek(fd,0,SEEK_SET);              /*初始化缓冲文件的读写位置*/

	if(!fork())  /*创建生产者进程*/
	{
		in = 0;	
		for(j=0;j<500;j++)
		{
			
			sem_wait(empty);
			sem_wait(mutex);
			lseek(fd,in*sizeof(int),SEEK_SET);
			write(fd,&j,sizeof(int));
			in = (in+1) % BUFFER_SIZE;
			sem_post(mutex);
			sem_post(full);
		}
		exit(0);
	}

	for(i=0;i<N;i++)   /*创建N个消费者进程*/
	{
		if(!fork())
		{		
			int num,pos;
			for(k=0;k<(500/N);k++)
			{
				sem_wait(full);
				sem_wait(mutex);
				sem_getvalue(out,&pos);
				lseek(fd,(pos%BUFFER_SIZE)*sizeof(int),SEEK_SET);
				read(fd,&num,sizeof(int));
				printf("%ld: %d\n",(long)getpid(),num);
				fflush(stdout);
				sem_post(out);
				sem_post(mutex);
				sem_post(empty);
			}
			exit(0);
		}
	}
	wait(NULL);
	
	sem_unlink("mutex");
	sem_unlink("full");
	sem_unlink("empty");
    sem_unlink("out");
	
	return 0;
}























	
